<?php

namespace app\model;

use Laf\Log;
use mon\orm\Model;
use mon\orm\db\Raw;
use mon\util\Instance;
use mon\orm\exception\DbException;

/**
 * 应用客服账号模型
 *
 * Class ChatUser
 * @copyright 2021-03-25 mon-console
 * @version 1.0.0
 */
class ChatWaiterModel extends Model
{
    use Instance;

    /**
     * 操作表
     *
     * @var string
     */
    protected $table = 'chat_waiter';

    /**
     * 新增自动写入字段
     *
     * @var array
     */
    protected $insert = ['register_ip', 'register_time', 'create_time', 'update_time'];

    /**
     * 更新自动写入字段
     *
     * @var array
     */
    protected $update = ['update_time'];

    /**
     * 验证器
     *
     * @var string
     */
    protected $validate = \app\validate\Chat::class;

    /**
     * 查询信息
     *
     * @param array $where where条件
     * @param mixed $field 查询字段
     * @return mixed
     */
    public function getInfo(array $where, $field = '*')
    {
        $info = $this->where($where)->field($field)->find();
        if (!$info) {
            $this->error = '账号不存在';
            return false;
        }

        return $info;
    }

    /**
     * 客服登录
     *
     * @param array $option 请求参数
     * @return mixed
     */
    public function login(array $option)
    {
        $check = $this->validate()->data($option)->scope('login')->check();
        if ($check !== true) {
            $this->error = $this->validate()->getError();
            return false;
        }

        // 获取用户信息
        $userInfo = $this->getInfo(['account' => $option['user']]);
        if (!$userInfo) {
            $this->error = '账号不存在';
            return false;
        }
        if ($userInfo['status'] != '1') {
            $this->error = '账号不可用';
            return false;
        }
        // 验证密码
        if ($userInfo['password'] != $this->encodePassword($option['password'])) {
            $this->error = '账号密码错误';
            return false;
        }
        // 验证允许登录IP段
        $ip = ip();
        if (!empty($userInfo['login_ip_limit']) && !safe_ip($ip, $userInfo['login_ip_limit'])) {
            $this->error = '当前环境不允许登录';
            return false;
        }
        // 更新用户信息
        $data = [
            'last_login_time'   => time(),
            'last_login_ip'     => $ip
        ];
        $save = $this->save($data, ['id' => $userInfo['id']]);
        if (!$save) {
            $this->error = '更新用户信息失败';
            return false;
        }

        return $userInfo;
    }

    /**
     * 修改用户密码
     *
     * @param array $option 请求参数
     * @param boolean $checkOld 是否验证旧密码，false表示管理员修改客服密码
     * @param integer $adminID 管理员iD
     * @return boolean
     */
    public function reset_password(array $option, $checkOld = false, $adminID = null)
    {
        $check = $this->validate()->data($option)->scope('reset_pwd')->check();
        if ($check !== true) {
            $this->error = $this->validate()->getError();
            return false;
        }

        // 获取用户信息
        $info = $this->getInfo(['id' => $option['idx']]);
        if (!$info) {
            $this->error = '获取用户信息失败';
            return false;
        }
        // 判断是否需要验证旧密码，需验证旧密码时，需要多传oldpwd参数
        if ($checkOld) {
            $old_pwd = isset($option['oldpwd']) ? $option['oldpwd'] : '';
            $checkOldPwd = $this->validate()->data(['password' => $old_pwd])->scope(['password'])->check();
            if ($checkOldPwd !== true) {
                $this->error = $this->validate()->getError();
                return false;
            }
            if ($info['password'] != $this->encodePassword($old_pwd)) {
                $this->error = '旧密码错误';
                return false;
            }
        }

        $this->startTrans();
        try {
            // 重新生成密码
            Log::instance()->oss(__FILE__, __LINE__, 'modify chat user password', 'sql');
            $save = $this->save(['password' => $this->encodePassword($option['password'])], ['id' => $option['idx']]);
            if (!$save) {
                $this->rollback();
                $this->error = '修改用户密码失败';
                return false;
            }

            // 记录操作日志
            if (!$checkOld && !is_null($adminID)) {
                $record = AdminLogModel::instance()->record(['action' => '修改客服人员账号密码', 'content' => '修改客服人员账号密码, 管理员ID：' . $adminID]);
                if (!$record) {
                    $this->rollback();
                    $this->error = '记录操作日志失败';
                    return false;
                }
            }

            $this->commit();
            return true;
        } catch (DbException $e) {
            $this->rollback();
            $this->error = '客服修改密码异常';
            Log::instance()->oss(__FILE__, __LINE__, 'modify chat user password exception, msg => ' . $e->getMessage(), 'error');
            return false;
        }
    }

    /**
     * 新增账号
     *
     * @param array $option
     * @param mixed $adminID 管理员ID，不为null则写入管理员日志
     * @return boolean
     */
    public function add(array $option, $adminID = null)
    {
        $check = $this->validate()->data($option)->scope('add_waiter')->check();
        if ($check !== true) {
            $this->error = $this->validate()->getError();
            return false;
        }

        // 判断名称是否已存在
        $userInfo = $this->where(['account' => $option['user']])->find();
        if ($userInfo) {
            $this->error = '用户名已存在';
            return false;
        }

        $this->startTrans();
        try {
            $save = $this->save([
                'account'       => $option['user'],
                'password'      => $this->encodePassword($option['password']),
                'nickname'      => $option['nickname'],
                'status'        => $option['status']
            ]);
            if (!$save) {
                $this->rollback();
                $this->error = '新增失败';
                return false;
            }

            // 管理员ID不为null，写入管理员日志
            if (!is_null($adminID)) {
                $record = AdminLogModel::instance()->record(['uid' => $adminID, 'action' => '新增客服应用客服人员账号', 'content' => '管理员新增客服应用人员账号：' . $option['user']]);
                if (!$record) {
                    $this->rollback();
                    $this->error = '记录日志失败';
                    return false;
                }
            }

            $this->commit();
            return true;
        } catch (DbException $e) {
            $this->rollback();
            $this->error = '新增客服账号异常';
            Log::instance()->oss(__FILE__, __LINE__, 'add chat user exception, msg => ' . $e->getMessage(), 'error');
            return false;
        }
    }

    /**
     * 修改客服人员账号
     *
     * @param array $option
     * @param mixed $adminID 管理员ID，不为null则写入管理员日志
     * @return boolean
     */
    public function edit(array $option, $adminID = null)
    {
        $check = $this->validate()->data($option)->scope('edit_waiter')->check();
        if ($check !== true) {
            $this->error = $this->validate()->getError();
            return false;
        }
        $result = [
            'account'   => $option['user'],
            'nickname'  => $option['nickname'],
            'status'    => $option['status']
        ];
        // 判断是否修改密码
        if (isset($option['password']) && !empty($option['password'])) {
            $checkPwd = $this->validate()->data($option)->scope('password')->check();
            if ($checkPwd !== true) {
                $this->error = $this->validate()->getError();
                return false;
            }

            $result['password'] = $this->encodePassword($option['password']);
        }

        // 判断名称是否已存在
        $userInfo = $this->where(['account' => $option['user']])->where('id', '<>', $option['idx'])->find();
        if ($userInfo) {
            $this->error = '名称已存在';
            return false;
        }

        try {
            $save = $this->save($result, ['id' => $option['idx']]);
            if (!$save) {
                $this->rollback();
                $this->error = '修改账号失败';
                return false;
            }

            // 管理员ID不为null，写入管理员日志
            if (!is_null($adminID)) {
                $record = AdminLogModel::instance()->record(['uid' => $adminID, 'action' => '修改客服应用客服人员账号', 'content' => '管理员修改客服应用人员账号：' . $option['user'] . '，账号ID：' . $option['idx']]);
                if (!$record) {
                    $this->rollback();
                    $this->error = '记录日志失败';
                    return false;
                }
            }

            $this->commit();
            return true;
        } catch (DbException $e) {
            $this->rollback();
            $this->error = '修改客服账号异常';
            Log::instance()->oss(__FILE__, __LINE__, 'edit chat user exception, msg => ' . $e->getMessage(), 'error');
            return false;
        }
    }

    /**
     * 查询列表
     *
     * @param array $option 请求参数
     * @return array
     */
    public function queryList(array $option)
    {
        $limit = isset($option['limit']) ? intval($option['limit']) : 10;
        $page = isset($option['page']) && is_numeric($option['page']) ? intval($option['page']) : 1;

        // 查询
        $list = $this->scope('list', $option)->page($page, $limit)->select();
        $total = $this->scope('list', $option)->count();

        return [
            'list'      => $list,
            'total'     => $total,
            'pageSize'  => $limit,
            'page'      => $page
        ];
    }

    /**
     * 查询列表场景
     *
     * @param [type] $query
     * @param [type] $args
     * @return $this
     */
    protected function scopeList($query, $args)
    {
        // ID搜索
        if (isset($args['idx']) && $args['idx'] != '' && is_numeric($args['idx']) && is_int($args['idx'] + 0)) {
            $query->where('id', intval($args['idx']));
        }
        // 应用ID
        if (isset($args['app_id']) && $args['app_id'] != '' && is_numeric($args['app_id']) && is_int($args['app_id'] + 0)) {
            $accessTable = ChatAccessModel::instance()->getTable();
            $query->where(new Raw("`id` IN (SELECT waiter_id FROM {$accessTable} WHERE app_id = {$args['app_id']})"));
        }
        // status搜索
        if (isset($args['status']) && $args['status'] != '' && is_numeric($args['status']) && is_int($args['status'] + 0)) {
            $query->where('status', intval($args['status']));
        }
        // 按账号
        if (isset($args['account']) && is_string($args['account']) && !empty($args['account'])) {
            $query->whereLike('account', trim($args['account']) . '%');
        }
        // 创建时间搜索
        if (isset($args['start_time']) && $args['start_time'] != '' && is_numeric($args['start_time']) && is_int($args['start_time'] + 0)) {
            $query->where('create_time', '>=', intval($args['start_time']));
        }
        if (isset($args['end_time']) && $args['end_time'] != '' && is_numeric($args['end_time']) && is_int($args['end_time'] + 0)) {
            $query->where('create_time', '<=', intval($args['end_time']));
        }
        // 排序
        if (isset($args['order']) && isset($args['sort']) && in_array($args['order'], ['create_time']) && in_array($args['sort'], ['asc', 'desc'])) {
            $query->order($args['order'], $args['sort']);
        }

        return $query;
    }

    /**
     * 混淆加密密码
     *
     * @param string $password 密码
     * @return string
     */
    public function encodePassword($password)
    {
        return md5($password);
    }

    /**
     * 自动完成create_time字段
     * 
     * @param mixed $val 默认值
     * @param array  $row 列值
     * @return string
     */
    protected function setCreateTimeAttr($val)
    {
        return time();
    }

    /**
     * 自动完成update_time字段
     * 
     * @param mixed $val 默认值
     * @param array  $row 列值
     * @return string
     */
    protected function setUpdateTimeAttr($val)
    {
        return time();
    }

    /**
     * 自动完成register_time字段
     * 
     * @param mixed $val 默认值
     * @param array  $row 列值
     * @return string
     */
    protected function setRegisterTimeAttr($val)
    {
        return time();
    }

    /**
     * 自动完成register_ip字段
     * 
     * @param mixed $val 默认值
     * @param array  $row 列值
     * @return string
     */
    protected function setRegisterIpAttr($val)
    {
        return ip();
    }
}
